# -*- encoding:utf-8 -*-
import random
from PIL import Image,ImageDraw
from makingrec.PearsonCor import clus_pearson
def readfile(filename):
    lines = [line for line in file(filename)]

    colnames = lines[0].split('\t')
    rownames = []
    data = []
    for line in lines[1:]:
        p=line.strip().split('\t')
        rownames.append(p[0])
        data.append([float(x) for x in p[1:]])

    return colnames,rownames,data
# 关键词检索
def readfile1(filename):
    lines = [line for line in file(filename)]

    data = {}
    title = lines[0].split('\t')[1:]
    for line in lines[1:]:

        data[line.split('\t')[0]] = dict(zip(title,[float(x) for x in line.split('\t')[1:]]))

    return data

# 聚类 类型
class bicluster:
    def __init__(self,vec,left=None,right=None,distance=0.0,id=None):
        self.left=left
        self.right=right
        self.vec=vec
        self.id=id
        self.distance=distance


# 聚类算法
def hcluster(rows,distance=clus_pearson):
    distances={}
    currentclustid=-1

    # 最开始的聚类就是数据集中的行
    clust=[bicluster(rows[i],id=i) for i in range(len(rows))]

    while len(clust)>1:
        # 设置最小配对以及最小距离的初始值
        lowestpair=(0,1)
        closest=distance(clust[0].vec,clust[1].vec)

        # 遍历每一个配对，找出最小距离
        for i in range(len(clust)):
            for j in range(i+1,len(clust)):
                if(clust[i].id,clust[j].id) not in distances:
                  distances[(clust[i].id,clust[j].id)]=distance(clust[i].vec,clust[j].vec)

                d=distances[(clust[i].id,clust[j].id)]
                if d<closest:
                    closest=d
                    lowestpair=(i,j)

        #计算两个聚类的平均值
        mergevec=[
            (clust[lowestpair[0]].vec[i]+clust[lowestpair[1]].vec[i])/2.0
            for i in range(len(clust[0].vec))]
        # 建新聚类
        newcluster = bicluster(mergevec,left=clust[lowestpair[0]],right=clust[lowestpair[1]],distance=closest,id=currentclustid)
        # 不在原始集合中的聚类，其id为负数
        currentclustid -=1
        del clust[lowestpair[1]]
        del clust[lowestpair[0]]
        clust.append(newcluster)

    return clust[0]


# 用PIL画出树类关系图
def getheight(clust):
  # Is this an endpoint? Then the height is just 1
  if clust.left==None and clust.right==None: return 1

  # Otherwise the height is the same of the heights of
  # each branch
  return getheight(clust.left)+getheight(clust.right)

def getdepth(clust):
  # The distance of an endpoint is 0.0
  if clust.left==None and clust.right==None: return 0

  # The distance of a branch is the greater of its two sides
  # plus its own distance
  return max(getdepth(clust.left),getdepth(clust.right))+clust.distance


def drawdendrogram(clust,labels,jpeg='clusters.jpg'):
  # height and width
  h=getheight(clust)*20
  w=1200
  depth=getdepth(clust)

  # width is fixed, so scale distances accordingly
  scaling=float(w-150)/depth

  # Create a new image with a white background
  img=Image.new('RGB',(w,h),(255,255,255))
  draw=ImageDraw.Draw(img)

  draw.line((0,h/2,10,h/2),fill=(255,0,0))

  # Draw the first node
  drawnode(draw,clust,10,(h/2),scaling,labels)
  img.save(jpeg,'JPEG')

def drawnode(draw,clust,x,y,scaling,labels):
  if clust.id<0:
    h1=getheight(clust.left)*20
    h2=getheight(clust.right)*20
    top=y-(h1+h2)/2
    bottom=y+(h1+h2)/2
    # Line length
    ll=clust.distance*scaling
    # Vertical line from this cluster to children
    draw.line((x,top+h1/2,x,bottom-h2/2),fill=(255,0,0))

    # Horizontal line to left item
    draw.line((x,top+h1/2,x+ll,top+h1/2),fill=(255,0,0))

    # Horizontal line to right item
    draw.line((x,bottom-h2/2,x+ll,bottom-h2/2),fill=(255,0,0))

    # Call the function to draw the left and right nodes
    drawnode(draw,clust.left,x+ll,top+h1/2,scaling,labels)
    drawnode(draw,clust.right,x+ll,bottom-h2/2,scaling,labels)
  else:
    # If this is an endpoint, draw the item label
    draw.text((x+5,y-7),labels[clust.id],(0,0,0))


# 是blogdata.txt中data的行与列翻转（转置矩阵）
def rotatematrix(data):
    newdata=[]
    for i in range(len(data[0])):
        newrow=[data[j][i] for j in range(len(data))]
        newdata.append(newrow)
    return newdata

# print [line for line in file('blogdata.txt')]
words,blognames,data=readfile('E:/python project/rexx/makingrec/cluster/blogdata.txt')
# rdata = rotatematrix(data)
# drawdendrogram(hcluster(rdata),words,jpeg='blogclust1.jpg')

# k-均值聚类过程
def kcluster(rows,distance=clus_pearson,k=4):
    # 确定每个点的最小值和最大值
    ranges=[(min([row[i] for row in rows]),max([row[i] for row in rows]))
            for i in range(len(rows[0]))]

    # 随机创建k个中心点
    clusters = [[random.random()*(ranges[i][1]-ranges[i][0]) + ranges[i][0]
    for i in range(len(rows[0]))] for j in range(k)]

    lastmatches=None
    for t in range(100):
        print 'Iteration %d' % t
        # 存储每次离各中心点距离近的点(ID)
        bestmatches=[[] for i in range(k)]

        # 在每一行中寻找距离最近的中心点
        for j in range(len(rows)):
            row=rows[j]
            # 表示与该点最近的中心点
            bestmatch=0
            # 遍历各个中心点与该点比较距离，找出与该点最近的中心点
            for i in range(k):
                d=distance(clusters[i],row)
                if d<distance(clusters[bestmatch],row):bestmatch=i
            # 把该点添加到聚簇中
            bestmatches[bestmatch].append(j)

        # 如果结果与上一次相同，则整个过程结束
        if bestmatches==lastmatches:break
        lastmatches=bestmatches

        # 把中心点移到其所有成员的平均位置处
        for i in range(k):
            avgs=[0.0]*len(rows[0])
            if len(bestmatches[i])>0:
                for rowid in bestmatches[i]:
                    for m in range(len(rows[rowid])):
                        avgs[m]+=rows[rowid][m]
                for j in range(len(avgs)):
                    avgs[j]/=len(bestmatches[i])
                clusters[i]=avgs

    return bestmatches


kclust = kcluster(data,k=10)
print [blognames[i] for i in kclust[0]]
print [blognames[i] for i in kclust[1]]
print [blognames[i] for i in kclust[2]]
print [blognames[i] for i in kclust[3]]
print [blognames[i] for i in kclust[4]]
print [blognames[i] for i in kclust[5]]
print [blognames[i] for i in kclust[6]]
print [blognames[i] for i in kclust[7]]
print [blognames[i] for i in kclust[8]]
print [blognames[i] for i in kclust[9]]

